﻿using System;
using System.Linq;
using UnityEngine;

namespace Tetris2020.Scripts.UI
{
    public class TetrisBox : MonoBehaviour
    {
        /// <summary>
        /// 方块类型
        /// </summary>
        [Tooltip("方块的类型, 包含[L, J, T, O, Z, S, I]七种类型")] [SerializeField]
        public BoxType type;

        [Tooltip("方块的状态. 用来管理方块的形态，")] [SerializeField] [Range(0, 4)]
        public int state;

        [Tooltip("方块的的相对坐标点, 根据中心旋转点核相对中心点的相对坐标，可以计算出方块的位置")] [SerializeField]
        public Vector2[] points;

        [Tooltip("方块的可变状态的操作列表. true:顺时针旋转90度, false:逆时针旋转90度")] [SerializeField]
        public RotateClockWise[] rotates;

        /// <summary>
        /// 方块的游戏逻辑坐标点. 是方块的旋转中心点的游戏坐标。
        /// </summary>
        public Vector2 Center { get; set; }

        /// <summary>
        ///  方块的游戏坐标点。
        /// </summary>
        public Vector2[] CurrentPosition { get; set; }

        private const int CenterOffset = 20;

        public const int BoxRectWeight = 40;

        private void Awake()
        {
            //    no-op
        }

        public void InitTetrisBox(Vector2 initCenter, int initState)
        {
            this.Center = initCenter;
            this.CurrentPosition = new Vector2[this.points.Length];
            for (var i = 0; i < points.Length; i++)
            {
                CurrentPosition[i] = new Vector2(this.Center.x + points[i].x, this.Center.y + points[i].y);
            }

            if (this.rotates.Length > 0)
            {
                var ts = initState % this.rotates.Length;
                while (this.state != ts)
                {
                    var position = CurrentPosition.Select(this.TryPreviewRotateBox)
                        .Where(vec => vec != default(Vector2)).ToArray();
                    this.OnRotateBox(position);
                }
            }

            this.RefreshTransformPosition();
        }

        public void OnTurnLeft(Vector2[] targetPosition)
        {
            this.Center -= Vector2.right;
            this.CurrentPosition = targetPosition;
            this.RefreshTransformPosition();
        }

        public void OnTurnRight(Vector2[] targetPosition)
        {
            this.Center += Vector2.right;
            this.CurrentPosition = targetPosition;
            this.RefreshTransformPosition();
        }

        public void OnTurnDown(Vector2[] targetPosition)
        {
            this.Center -= Vector2.up;
            this.CurrentPosition = targetPosition;
            this.RefreshTransformPosition();
        }

        public void OnRotateBox(Vector2[] targetPosition)
        {
            this.transform.Rotate(
                RotateClockWise.RcwTrue == rotates[state]
                    ? new Vector3(0, 0, -90)
                    : new Vector3(0, 0, 90));
            this.state = state + 1 >= rotates.Length ? 0 : state + 1;
            this.CurrentPosition = targetPosition;
        }

        public Vector2 TryPreviewRotateBox(Vector2 point)
        {
            if (this.rotates.Length <= 0)
                return default(Vector2);
            var isClockWise = RotateClockWise.RcwTrue == rotates[state];
            var angle = isClockWise ? Math.PI / 2 : -Math.PI / 2;
            return this.BoxRotate(point, this.Center, angle);
        }

        protected void RefreshTransformPosition()
        {
            var x = Center.x * BoxRectWeight + CenterOffset;
            var y = Center.y * BoxRectWeight + CenterOffset;
            ((RectTransform) this.transform).anchoredPosition = new Vector3(x, y, 0);
//            Debug.Log(this.transform.position);
        }

        /// <summary>
        /// 根据中心点选择
        /// </summary>
        /// <param name="center">中心点</param>
        /// <param name="point">当前点</param>
        /// <param name="angle">角度的弧度</param>
        /// <returns></returns>
        protected Vector2 BoxRotate(Vector2 point, Vector2 center, double angle)
        {
            /**
             * 复数法： 
             * http://www.topschool.org/sx/sx/200904/1601.html
             * http://www.tesoon.com/ask/htm/04/16403.htm
             */
            angle = -angle;
            var result = default(Vector2);
#if !USE_COMPLEX
            // 方式一：实现复数乘法计算
            var x = (float) ((point.x - center.x) * Math.Cos(angle) - (point.y - center.y) * Math.Sin(angle));
            var y = (float) ((point.x - center.x) * Math.Sin(angle) + (point.y - center.y) * Math.Cos(angle));
            result = new Vector2(center.x + x, center.y + y);
#else
        //    方式二：利用复数类进行计算
        var complex =
 new Complex(point.x - center.x, point.y - center.y) * new Complex(Math.Cos(angle), Math.Sin(angle)) + new Complex(center.x, center.y);
        result = new Vector2((float)complex.Real, (float)complex.Image);
#endif
            return result;
        }
    }

    /// <summary>
    /// 是否顺时针旋转.
    /// true:顺时针旋转90度, false:逆时针旋转90度
    /// </summary>
    public enum RotateClockWise
    {
        [Tooltip("顺时针旋转90度")] RcwTrue,
        [Tooltip("逆时针旋转90度")] RcwFalse
    }
}